aegida-console / app / api / attachments / [id] / route.ts
route.ts
Raw
import { AuthError, authenticateRequest } from "@/lib/auth/server";
import { GateFileError, getGateFileContent } from "@/lib/chat/gate-files";
import { getOwnedAttachment } from "@/lib/db/attachments";
import { getPool } from "@/lib/db/pool";
import { getAttachmentObject } from "@/lib/storage/s3";

export const runtime = "nodejs";
const noStoreHeaders = { "Cache-Control": "no-store" };

export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }): Promise<Response> {
  try {
    const user = await authenticateRequest(request);
    const authorization = request.headers.get("Authorization");
    if (!authorization) throw new AuthError();
    const attachment = await getOwnedAttachment(getPool(), user.id, (await params).id);
    if (!attachment) {
      return Response.json(
        { error: "Вложение не найдено" },
        { status: 404, headers: noStoreHeaders },
      );
    }

    const content = attachment.gateFileId
      ? await getGateFileContent(attachment.gateFileId, authorization, request.signal)
      : attachment.objectKey
        ? await getAttachmentObject(attachment.objectKey)
        : null;
    if (!content) throw new Error("Attachment has no storage reference");

    return new Response(content, {
      headers: {
        ...noStoreHeaders,
        "Content-Disposition": `attachment; filename*=UTF-8''${encodeFilename(attachment.name)}`,
        "Content-Length": String(attachment.size),
        "Content-Type": attachment.contentType,
        "X-Content-Type-Options": "nosniff",
      },
    });
  } catch (error) {
    return Response.json(
      {
        error:
          error instanceof AuthError ||
          (error instanceof GateFileError && error.reason === "unauthorized")
            ? "Unauthorized"
            : "Хранилище вложений временно недоступно",
      },
      {
        status:
          error instanceof AuthError ||
          (error instanceof GateFileError && error.reason === "unauthorized")
            ? 401
            : 503,
        headers: noStoreHeaders,
      },
    );
  }
}

function encodeFilename(value: string): string {
  return encodeURIComponent(value).replace(/[!'()*]/g, (character) =>
    `%${character.charCodeAt(0).toString(16).toUpperCase()}`,
  );
}